﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Lm.InferenceEngine
{
    public class InferenceComputer
    {
        /// <summary>
        /// 所有可能性树形结构的根
        /// </summary>
        InferenceObject Root { get; set; }
        public InferenceComputer(InferenceObject obj)
        {
            this.Root = obj;
        }

        /// <summary>
        /// 遍历所有的树形分支节点，查看节点是不是达到目标，达到目标的标记为Success。
        /// 使推理陷入死循环的标记为End，
        /// 处理完成的也标记为End，
        /// 计算完成后调用GetResult获取成功的节点
        /// </summary>
        public void Compute()
        {
            while (true)
            {
                var normalObject = this.FindOneNormalDescendantObject(this.Root);
                if (normalObject == null)
                {
                    break;
                }
                else
                {
                    var childrens = normalObject.GenerateChildrens();
                    foreach (var child in childrens)
                    {
                        child.Parent = normalObject;
                        if (child.IsSuccess())
                        {
                            child.Status = InferenceStatus.Success;
                        }
                        else
                        {
                            var ancestor = this.FindSameAncestor(child, child.Parent);
                            if (ancestor == null)
                            {
                                child.Status = InferenceStatus.Normal;
                            }
                            else
                            {
                                child.Status = InferenceStatus.End;
                            }
                        }
                    }
                    normalObject.Childrens = childrens;
                    normalObject.Status = InferenceStatus.End;
                }
            }
        }

        /// <summary>
        /// 计算完成后调用GetResult获取成功的节点
        /// </summary>
        /// <returns></returns>
        public List<InferenceObject> GetResult()
        {
            var successList = new List<InferenceObject>();
            this.FindAllSuccessDescendant(this.Root, successList);
            return successList;
        }

        /// <summary>
        /// 找到所有成功的节点
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="successList"></param>
        protected void FindAllSuccessDescendant(InferenceObject obj, List<InferenceObject> successList)
        {
            if (obj.Status == InferenceStatus.Success)
            {
                successList.Add(obj);
            }
            else
            {
                if (obj.Childrens != null)
                {
                    foreach (var child in obj.Childrens)
                    {
                        this.FindAllSuccessDescendant(child, successList);
                    }
                }
            }
        }

        /// <summary>
        /// 找到和自己相同的祖先，
        /// 如果存在，就会使推理陷入死循环，
        /// 那么把这个节点标记为失败。
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected InferenceObject FindSameAncestor(InferenceObject obj, InferenceObject ancestor)
        {
            if (obj.SameWith(ancestor))
            { return ancestor; }
            else
            {
                if (ancestor.Parent != null)
                {
                    return this.FindSameAncestor(obj, ancestor.Parent);
                }
                else
                { return null; }
            }
        }
        /// <summary>
        /// 找到一个正常的（状态为Normal）后代，也就是待处理的节点
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected InferenceObject FindOneNormalDescendantObject(InferenceObject obj)
        {
            if (obj.Status == InferenceStatus.Normal)
            { return obj; }
            if (obj.Childrens != null)
            {
                foreach (var child in obj.Childrens)
                {
                    var r = this.FindOneNormalDescendantObject(child);
                    if (r == null)
                    { continue; }
                    else
                    {
                        return r;
                    }
                }
                return null;
            }
            else
            { return null; }
        }        
    }
}
